package com.example.demo;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.example.demo.config.AbilityGateway;
import com.example.demo.config.AbilityOperation;
import com.example.demo.utils.JsonUtils;
import com.example.demo.utils.SecurityUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.*;

import static cn.hutool.core.date.DatePattern.PURE_DATETIME_FORMAT;

@Service
public class LoginService {
    private static final Logger logger = LoggerFactory.getLogger(LoginService.class);

    private final RestTemplate restTemplate;

    private final AbilityOperation abilityOperation;

    private final AbilityGateway abilityGateway;

    public LoginService(RestTemplate restTemplate, AbilityOperation abilityOperation, AbilityGateway abilityGateway) {
        this.restTemplate = restTemplate;
        this.abilityOperation = abilityOperation;
        this.abilityGateway = abilityGateway;
    }

//    @PostConstruct
//    public void initial() {
//        try {
//            getAppToken();
//        } catch (Exception e) {
//            logger.error("{}", e);
//            throw new RuntimeException(e);
//        }
//    }

    /**
     * 获取能力网关AccessToken
     *
     * @return String
     * @throws Exception
     */
    public String getAccessToken() throws Exception {
        String dynamicToken = getDynamicToken();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        String format = DateUtil.format(new Date(), PURE_DATETIME_FORMAT);
        Map<String, Object> params = new LinkedHashMap<>();
        Map<String, Object> reqParam = new LinkedHashMap<>();
        Map<String, Object> busiInfo = new LinkedHashMap<>();
        busiInfo.put("grant_type", "client_credentials");
        busiInfo.put("app_id", abilityGateway.getAppid());
        busiInfo.put("app_key", abilityGateway.getAppKey());
        params.put("REQ_PARAM", reqParam);
        reqParam.put("BUSI_INFO", busiInfo);
        reqParam.put("PUB_INFO", new HashMap<String, Object>() {{
            put("OP_CODE", "***");
            put("CHANNEL_ID", "***");
            put("OP_ORG_ID", "***");
            put("REQ_TIME", format);
            put("REQ_SERIAL_NO", IdUtil.fastSimpleUUID());

        }});
        reqParam.put("PAGE_INFO", new HashMap<>(0));
        String url = abilityOperation.getUrl() + "/oppf?timestamp=" + format + "&flowid=" + System.currentTimeMillis() + "&appId=" + abilityOperation.getAppid() + "&accessToken=" + dynamicToken + "&method=GANS_UNOT_T_oauthToken&format=json";
        String encodedValue = SecurityUtils.encodeAES256HexUpper(JsonUtils.obj2String(params), SecurityUtils.decodeHexUpper(abilityOperation.getAccessToken()));
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, new HttpEntity<>(encodedValue, headers), String.class);
        String decodeValue = SecurityUtils.decodeAES256HexUpper(Objects.requireNonNull(responseEntity.getBody()), SecurityUtils.decodeHexUpper(abilityOperation.getAccessToken()));
        Map<String, Object> result = JsonUtils.string2Obj(decodeValue, new TypeReference<Map<String, Object>>() {
        });
        Map<String, Object> rspParam = (Map<String, Object>) result.get("RSP_PARAM");
        Map<String, Object> rspBusiInfo = (Map<String, Object>) rspParam.get("BUSI_INFO");
        return rspBusiInfo.get("access_token").toString();
    }


    /**
     * 申请AppToken接口
     */
    public void getAppToken() throws Exception {
        String accessToken = getAccessToken();
        String dynamicToken = getDynamicToken();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        String format = DateUtil.format(new Date(), PURE_DATETIME_FORMAT);
        Map<String, Object> params = new LinkedHashMap<>();
        Map<String, Object> reqParam = new LinkedHashMap<>();
        Map<String, Object> busiInfo = new LinkedHashMap<>();
        Map<String, Object> hend = new LinkedHashMap<>();
        hend.put("method", "M_ABILITY_UNIUSER_200000023");
        hend.put("format", "json");
        hend.put("appId", abilityGateway.getAppid());
        hend.put("openId", "111");
        hend.put("operId", "111");
        hend.put("version", "V1.0");
        hend.put("accessToken", accessToken);
        hend.put("sign", "SHA");
        hend.put("timestamp", format);
        busiInfo.put("hend", hend);
        busiInfo.put("clientId", "uni_574_gs_rms");
        busiInfo.put("clientSecret", "U2FsdGVkX18TCsMyohE8nk28WCoEhzv8jiXHW2Zazzw=");
        busiInfo.put("targetClientId", "uni_246_RMS");
        busiInfo.put("grant_type", "client_credentials");
        busiInfo.put("app_id", abilityGateway.getAppid());
        busiInfo.put("app_key", abilityGateway.getAppKey());
        params.put("REQ_PARAM", reqParam);
        reqParam.put("BUSI_INFO", busiInfo);
        reqParam.put("PUB_INFO", new HashMap<String, Object>() {{
            put("OP_CODE", "***");
            put("CHANNEL_ID", "***");
            put("OP_ORG_ID", "***");
            put("REQ_TIME", format);
            put("REQ_SERIAL_NO", IdUtil.fastSimpleUUID());

        }});
        reqParam.put("PAGE_INFO", new HashMap<>(0));
        String url = abilityOperation.getUrl() + "/oppf?timestamp=" + format + "&flowid=" + System.currentTimeMillis() + "&appId=" + abilityOperation.getAppid() + "&accessToken=" + dynamicToken + "&method=GANS_UNOT_T_apptokenAcquire&format=json";

        logger.debug("URL: {}", url);

        logger.debug("Request: {}", JsonUtils.obj2StringPretty(params));

        String encodedValue = SecurityUtils.encodeAES256HexUpper(JsonUtils.obj2String(params), SecurityUtils.decodeHexUpper(accessToken));
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, new HttpEntity<>(encodedValue, headers), String.class);

        logger.debug("Response: {}", JsonUtils.obj2StringPretty(responseEntity));

        String decodeValue = SecurityUtils.decodeAES256HexUpper(Objects.requireNonNull(responseEntity.getBody()), SecurityUtils.decodeHexUpper(accessToken));

        logger.debug("Decode: {}", JsonUtils.obj2StringPretty(decodeValue));

        Map<String, Object> result = JsonUtils.string2Obj(decodeValue, new TypeReference<Map<String, Object>>() {
        });

        System.out.println(JsonUtils.obj2StringPretty(result));

        Map<String, Object> rspParam = (Map<String, Object>) result.get("RSP_PARAM");

        Map<String, Object> rspBusiInfo = (Map<String, Object>) rspParam.get("BUSI_INFO");

        System.out.println(JsonUtils.obj2StringPretty(rspBusiInfo));
    }

    private String getDynamicToken() {
        Map<String, String> params = new HashMap<>(3);
        params.put("appId", abilityOperation.getAppid());
        params.put("accessToken", abilityOperation.getAccessToken());
        params.put("Flag", "opcf");

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(
                abilityOperation.getUrl() + "/opcfapi/V1/partner/ability/dynamicToken",
                new HttpEntity<>(JsonUtils.obj2String(params), headers),
                String.class);
        Map<String, String> result = JsonUtils.string2Obj(responseEntity.getBody(), new TypeReference<HashMap<String, String>>() {
        });
        return Objects.requireNonNull(result).get("dynamicToken");
    }
}
